    <!DOCTYPE html>
<html lang="zh-cn">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<meta name="author" content="nodejh">
		<meta name="description" content="My Blog">
		<meta name="generator" content="Hugo 0.31.1" />
		<title>使用 Python and Keras 构建一个简单的神经网络 &middot; nodejh</title>
		<link rel="shortcut icon" href="http://nodejh.com/images/favicon.ico">
		<link rel="stylesheet" href="http://nodejh.com/css/style.css">
		<link rel="stylesheet" href="http://nodejh.com/css/highlight.css">
		

		
		<link rel="stylesheet" href="http://nodejh.com/css/font-awesome.min.css">
		

		
		<link href="http://nodejh.com/index.xml" rel="alternate" type="application/rss+xml" title="nodejh" />
		
	</head>

    <body>
       <nav class="main-nav">
	
	
		<a href='http://nodejh.com/'> <span class="arrow">←</span>Home</a>
	
	<a href='http://nodejh.com/post'>Archive</a>
	<a href='http://nodejh.com/tags'>Tags</a>
	<a href='http://nodejh.com/projects'>Projects</a>
	<a href='http://nodejh.com/about'>About</a>

	

	
	<a class="cta" href="http://nodejh.com/index.xml">Subscribe</a>
	
</nav>


        <section id="wrapper" class="post">
            <article>
                <header>
                    <h1>
                        使用 Python and Keras 构建一个简单的神经网络
                    </h1>
                    <h2 class="headline">
                    Oct 9, 2016 18:27
                    · 3092 words
                    · 7 minutes read
                      <span class="tags">
                      
                      
                          
                              <a href="http://nodejh.com/tags/nerual-network">Nerual Network</a>
                          
                              <a href="http://nodejh.com/tags/python">Python</a>
                          
                      
                      
                      </span>
                    </h2>
                </header>
                
                  
                    <div id="toc">
                      <nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#1-使用-python-and-keras-构建-一个简单的神经网络">1. 使用 Python and Keras 构建 一个简单的神经网络</a></li>
<li><a href="#2-前馈神经网络">2. 前馈神经网络</a></li>
<li><a href="#3-使用-python-和-keras-实现我们的神经网络">3. 使用 Python 和 Keras 实现我们的神经网络</a></li>
<li><a href="#4-使用构建的神经网络来分类图片">4. 使用构建的神经网络来分类图片</a></li>
<li><a href="#5-总结">5. 总结</a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</nav>
                    </div>
                  
                
                <section id="post-body">
                    <blockquote>
<p>本文翻译自 <a href="http://www.pyimagesearch.com/2016/09/26/a-simple-neural-network-with-python-and-keras/">A simple neural network with Python and Keras</a></p>
</blockquote>

<p></p>

<p><img src="http://oh1ywjyqf.bkt.clouddn.com/blog/2016-11-22-a-simple-neural-network-with-python-and-keras-1.png" alt="a-simple-neural-network-with-python-and-keras-1" /></p>

<h4 id="1-使用-python-and-keras-构建-一个简单的神经网络">1. 使用 Python and Keras 构建 一个简单的神经网络</h4>

<p>在开始之前，我们先快速复习一下当前最通用的神经网络架构：前馈网络。</p>

<p>我们接下来将写一个 Python 代码来定义我们的前馈神经网络，然后将其运用到 Kaggle Dogs vs. Cats(<a href="https://www.kaggle.com/c/dogs-vs-cats/data">https://www.kaggle.com/c/dogs-vs-cats/data</a>) 分类比赛中。这比赛的目标是，给出一张图像，然后区分它是猫还是狗。</p>

<p>最后，我们将检查我们的神经网络程序的区分结果，然后再讨论一下如何继续优化我们的架构，使结构更精确。</p>

<h4 id="2-前馈神经网络">2. 前馈神经网络</h4>

<p>目前有很多很多的神经网络架构，其中最通用的一种架构是前馈网络。</p>

<p><img src="http://oh1ywjyqf.bkt.clouddn.com/blog/2016-11-22-a-simple-neural-network-with-python-and-keras-2.png" alt="a-simple-neural-network-with-python-and-keras-2" /></p>

<p>上图是一个简单的前馈神经网络示意图，该前馈网络具有三个输入节点，一个具有两个节点的隐藏层，一个具有三个节点的隐藏层，还有两个节点的输出层。</p>

<p>在这种类型的架构中，要在这两个节点之间建立连接，必须要求这两个节点是 <code>layer i</code> 中的节点连接到 <code>layer i+1</code> 中的节点（这也是前馈网络这个术语的由来；前馈网络不允许反向连接，或者层内连接）。</p>

<p>并且，<code>layer i</code> 中的节点，必须完全连接（fully connected）到 <code>layer i+1</code> 中的节点。也就是说，<code>layer i</code> 中的每一个节点，必须连接到 <code>layer i+1</code> 中的每个节点。如上图所示，在 layer 0 和 layer 1 中，一共有 2 x 3 = 6 个节点 &mdash; 这就是完全连接（fully connected），或者可以缩写为 <code>FC</code>。</p>

<p>我们通常使用一系列的整数来快速简洁地描述每个 layer 中的节点。</p>

<p>例如，上图的前馈网络，我们可以称之为 <code>3-2-3-2前馈神经网络</code>：</p>

<ul>
<li>Layer 0 包含 3 个输入，我们可将其定义为 Xi。这些输入值可能是特征矢量的原始像素强度或矢量条目。</li>
<li>Layer 1 和 Layer 2 是隐藏层（hidden layers），分别包含两个和三个节点。</li>
<li>Layer 3 是输出节层（output layer），或叫可见层（output layer）。在这里网们将获得神经网络输出的分类。输出层可能有很多输出节点，每一个分类都对应着一个潜在的输出。在  Kaggle Dogs vs. Cats 的分类中，我们有两个输出节点，猫和狗。如果还有其他分类，就会有另一个与之对应的输出节点。</li>
</ul>

<h4 id="3-使用-python-和-keras-实现我们的神经网络">3. 使用 Python 和 Keras 实现我们的神经网络</h4>

<p>现在我们已经理解了前馈神经网络的基本知识，接下来让我们使用  Python 和 Keras 实现我们用于图像分类的神经网络。</p>

<p>在开始之前，你需要在你的电脑上安装 <code>Keras</code> 这个框架。</p>

<p>接下来，新建一个名为 <code>simple_neural_network.py</code> 的文件，然后开始编码：</p>

<pre><code># import the necessary packages
from sklearn.preprocessing import LabelEncoder
from sklearn.cross_validation import train_test_split
from keras.models import Sequential
from keras.layers import Activation
from keras.optimizers import SGD
from keras.layers import Dense
from keras.utils import np_utils
from imutils import paths
import numpy as np
import argparse
import cv2
import os
</code></pre>

<p>在这段代码中，我们引入我们需要的 Python 的包。我们将使用 scikit-learn 和 Keras 来一起实现我们的函数。在这之前，你最好也需要知道怎么配置开发环境中的 Keras。</p>

<p>同时我们也需要用刀 <code>imutils</code> 这个包，这个包可以方便我们使用 OpenCV。如果你还没有安装 imutils，则先安装：</p>

<pre><code>pip install imutils
</code></pre>

<p>接下来，我们需要定义一个函数，来接收图像，并且得到图像的原始像素强度。</p>

<p>为了完成这个目标，我们先定一个名为 <code>image_to_feature_vector</code> 的函数，它接受两个输入，一个是 <code>image</code>，另一个是 <code>size</code>：</p>

<pre><code>def image_to_feature_vector(image, size=(32, 32)):
	# resize the image to a fixed size, then flatten the image into
	# a list of raw pixel intensities
	return cv2.resize(image, size).flatten()

</code></pre>

<p>我们将调整图像，使我们收集到的图像都具有相同的矢量特征大小。这也是我们使用神经网络的一个先决条件，每张图像都必须由一个矢量来表示。</p>

<p>在这个函数里面，我们需要将图像调整为 32 x 32 像素，然后将图像转化为 32 x 32 x 3 = 3,072-d  的特征矢量。</p>

<p>接下来的代码，将处理解析命令行参数，注意其中的一些初始化操作：</p>

<pre><code># construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(&quot;-d&quot;, &quot;--dataset&quot;, required=True,
	help=&quot;path to input dataset&quot;)
args = vars(ap.parse_args())

# grab the list of images that we'll be describing
print(&quot;[INFO] describing images...&quot;)
imagePaths = list(paths.list_images(args[&quot;dataset&quot;]))

# initialize the data matrix and labels list
data = []
labels = []

</code></pre>

<p>我们使用 <code>--dataset</code> 参数来定义输入  Kaggle Dogs vs. Cats 图像的目录。这些图像图可以从 <a href="https://www.kaggle.com/c/dogs-vs-cats/data">https://www.kaggle.com/c/dogs-vs-cats/data</a> 这里下载。</p>

<p><code>imagePaths = list(paths.list_images(args[&quot;dataset&quot;]))</code> 这一行用来收集输入的图像。第 31 行 和第 32 分别初始化 <code>data</code> 和 <code>labels</code> 列表。</p>

<p>现在我们已经有了 <code>imagePaths</code>，接下来就可以循环处理它们中的每一项，把图像转换为特征矢量，然后将其添加到 <code>data</code>  和 <code>labels</code> 列表：</p>

<pre><code># loop over the input images
for (i, imagePath) in enumerate(imagePaths):
	# load the image and extract the class label (assuming that our
	# path as the format: /path/to/dataset/{class}.{image_num}.jpg
	image = cv2.imread(imagePath)
	label = imagePath.split(os.path.sep)[-1].split(&quot;.&quot;)[0]

	# construct a feature vector raw pixel intensities, then update
	# the data matrix and labels list
	features = image_to_feature_vector(image)
	data.append(features)
	labels.append(label)

	# show an update every 1,000 images
	if i &gt; 0 and i % 1000 == 0:
		print(&quot;[INFO] processed {}/{}&quot;.format(i, len(imagePaths)))
</code></pre>

<p>现在 <code>data</code> 列表包含每个输入图像的扁平化  32 x 32 x 3 = 3,072-d 表示。当然，在我们开始训练我们的神经网络之前，我们首先要做一些预处理：</p>

<pre><code># encode the labels, converting them from strings to integers
le = LabelEncoder()
labels = le.fit_transform(labels)

# scale the input image pixels to the range [0, 1], then transform
# the labels into vectors in the range [0, num_classes] -- this
# generates a vector for each label where the index of the label
# is set to `1` and all other entries to `0`
data = np.array(data) / 255.0
labels = np_utils.to_categorical(labels, 2)

# partition the data into training and testing splits, using 75%
# of the data for training and the remaining 25% for testing
print(&quot;[INFO] constructing training/testing split...&quot;)
(trainData, testData, trainLabels, testLabels) = train_test_split(
	data, labels, test_size=0.25, random_state=42)
</code></pre>

<p><code>data = np.array(data) / 255.0</code> 行将输入的数据范围调整到 [0, 1] 之间，<code>labels = np_utils.to_categorical(labels, 2)</code>  这一行将整数转换为矢量（在我们训练神经网络的交叉熵损失函数中需要用到）。</p>

<p>接下来的两行，我们就开始初始化我们的训练和测试代码，75% 的数据用来训练，25% 的数据用来测试。</p>

<p>现在我们将使用 Keras 来定义我们的神经网络：</p>

<pre><code># define the architecture of the network
model = Sequential()
model.add(Dense(768, input_dim=3072, init=&quot;uniform&quot;,
	activation=&quot;relu&quot;))
model.add(Dense(384, init=&quot;uniform&quot;, activation=&quot;relu&quot;))
model.add(Dense(2))
model.add(Activation(&quot;softmax&quot;))
</code></pre>

<p>上面的代码就即用来构建我们的神经网络结构，一个 3072-768-384-2 前馈神经网络。</p>

<p>我们的 input layer 有 3072 个节点，在我们输入的扁平化图像厘米，每个节点有 32 x 32 x 3 = 3,072 个原始像素强度。</p>

<p>我们也有两个 hidden layer，分别有 768 和 384 个节点。这些节点的数目通过交叉验证和调整超参数实验来确定。</p>

<p>Output layer 包含两个节点，分别是猫和狗的类标签。</p>

<p>我们将在网络的顶部定义一个名为 <code>softmax</code> 的函数，这个函数将会得出实际输出类标签的概率。</p>

<p>接下来将使用 <a href="https://en.wikipedia.org/wiki/Stochastic_gradient_descent">Stochastic Gradient Descent (SGD)</a> 来训练我们的模型：</p>

<pre><code># train the model using SGD
print(&quot;[INFO] compiling model...&quot;)
sgd = SGD(lr=0.01)
model.compile(loss=&quot;binary_crossentropy&quot;, optimizer=sgd,
	metrics=[&quot;accuracy&quot;])
model.fit(trainData, trainLabels, nb_epoch=50, batch_size=128,
</code></pre>

<p>为了训练我们的模型，我们将SGD的学习率参数设定为0.01。我们将使用 binary_crossentropy 损失函数也是如此。</p>

<p>在大多数情况下，你需要使用交叉熵 <code>crossentropy</code> ，但由于只有两个类标签，所以我们使用 <code>binary_crossentropy</code>。如果类标签数量大于 2，请确保使用交叉熵。</p>

<p>这个网络允许对 50 epochs 进行训练，意味着模型将看到对每个图片单独进行 50 次训练，以便了解底层的图案。</p>

<p>最后的代码块评估我们的Keras神经网络的测试数据：</p>

<pre><code># show the accuracy on the testing set
print(&quot;[INFO] evaluating on testing set...&quot;)
(loss, accuracy) = model.evaluate(testData, testLabels,
	batch_size=128, verbose=1)
print(&quot;[INFO] loss={:.4f}, accuracy: {:.4f}%&quot;.format(loss,
	accuracy * 100))
</code></pre>

<h4 id="4-使用构建的神经网络来分类图片">4. 使用构建的神经网络来分类图片</h4>

<p>为了使用 <code>simple_neural_network.py</code> 这个脚本，请确保：</p>

<ul>
<li>使用完整代码</li>
<li>下载  Kaggle Dogs vs. Cats <a href="[https://www.kaggle.com/c/dogs-vs-cats/data](https://www.kaggle.com/c/dogs-vs-cats/data)"><a href="https://www.kaggle.com/c/dogs-vs-cats/data">https://www.kaggle.com/c/dogs-vs-cats/data</a></a>  的图像，并保存在某个目录如 kaggle_dogs_vs_cats</li>
</ul>

<p>完整代码如下：</p>

<pre><code># USAGE
# python simple_neural_network.py --dataset kaggle_dogs_vs_cats

# import the necessary packages
from sklearn.preprocessing import LabelEncoder
from sklearn.cross_validation import train_test_split
from keras.models import Sequential
from keras.layers import Activation
from keras.optimizers import SGD
from keras.layers import Dense
from keras.utils import np_utils
from imutils import paths
import numpy as np
import argparse
import cv2
import os

def image_to_feature_vector(image, size=(32, 32)):
	# resize the image to a fixed size, then flatten the image into
	# a list of raw pixel intensities
	return cv2.resize(image, size).flatten()

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(&quot;-d&quot;, &quot;--dataset&quot;, required=True,
	help=&quot;path to input dataset&quot;)
args = vars(ap.parse_args())

# grab the list of images that we'll be describing
print(&quot;[INFO] describing images...&quot;)
imagePaths = list(paths.list_images(args[&quot;dataset&quot;]))

# initialize the data matrix and labels list
data = []
labels = []

# loop over the input images
for (i, imagePath) in enumerate(imagePaths):
	# load the image and extract the class label (assuming that our
	# path as the format: /path/to/dataset/{class}.{image_num}.jpg
	image = cv2.imread(imagePath)
	label = imagePath.split(os.path.sep)[-1].split(&quot;.&quot;)[0]

	# construct a feature vector raw pixel intensities, then update
	# the data matrix and labels list
	features = image_to_feature_vector(image)
	data.append(features)
	labels.append(label)

	# show an update every 1,000 images
	if i &gt; 0 and i % 1000 == 0:
		print(&quot;[INFO] processed {}/{}&quot;.format(i, len(imagePaths)))

# encode the labels, converting them from strings to integers
le = LabelEncoder()
labels = le.fit_transform(labels)

# scale the input image pixels to the range [0, 1], then transform
# the labels into vectors in the range [0, num_classes] -- this
# generates a vector for each label where the index of the label
# is set to `1` and all other entries to `0`
data = np.array(data) / 255.0
labels = np_utils.to_categorical(labels, 2)

# partition the data into training and testing splits, using 75%
# of the data for training and the remaining 25% for testing
print(&quot;[INFO] constructing training/testing split...&quot;)
(trainData, testData, trainLabels, testLabels) = train_test_split(
	data, labels, test_size=0.25, random_state=42)

# define the architecture of the network
model = Sequential()
model.add(Dense(768, input_dim=3072, init=&quot;uniform&quot;,
	activation=&quot;relu&quot;))
model.add(Dense(384, init=&quot;uniform&quot;, activation=&quot;relu&quot;))
model.add(Dense(2))
model.add(Activation(&quot;softmax&quot;))

# train the model using SGD
print(&quot;[INFO] compiling model...&quot;)
sgd = SGD(lr=0.01)
model.compile(loss=&quot;binary_crossentropy&quot;, optimizer=sgd,
	metrics=[&quot;accuracy&quot;])
model.fit(trainData, trainLabels, nb_epoch=50, batch_size=128,
	verbose=1)

# show the accuracy on the testing set
print(&quot;[INFO] evaluating on testing set...&quot;)
(loss, accuracy) = model.evaluate(testData, testLabels,
	batch_size=128, verbose=1)
print(&quot;[INFO] loss={:.4f}, accuracy: {:.4f}%&quot;.format(loss,
	accuracy * 100))
</code></pre>

<p>然后，就可以像下面这样运行：</p>

<pre><code>python simple_neural_network.py --dataset kaggle_dogs_vs_cats
</code></pre>

<p>运行后的程序输出如下：</p>

<p><img src="http://oh1ywjyqf.bkt.clouddn.com/blog/2016-11-22-a-simple-neural-network-with-python-and-keras-3.png" alt="a-simple-neural-network-with-python-and-keras-3" /></p>

<p>在我的 Titan X GPU 的电脑上，整个程序的执行，包括特征提取、训练神经网络、评估测试数据，一共花了 1m 15s。训练数据的准确率大约为 76%，测试数据的准确率大约为 67%。</p>

<p>大概 9% 的准确率差异，也是很常见的，这跟训练测试精度，和有限的测试数据相关。</p>

<p>在上面的程序中，我们最终获得了 67.376％ 的精度，这也是比较高的精度了。当然，我们还可以很容易地通过使用卷积神经网络获得大于 95％ 的准确率。</p>

<h4 id="5-总结">5. 总结</h4>

<p>在上面的内容中，我示范了如何通过 Python and Keras 来构建和训练神经网络。我们将神经网络运用到了 Kaggle Dogs vs. Cats 的测试中，仅仅通过每张图片的原始像素强度，我们就最终得到了  67.376% 的精度。</p>

<hr />

<p>Github Issue: <a href="https://github.com/nodejh/nodejh.github.io/issues/3">https://github.com/nodejh/nodejh.github.io/issues/3</a></p>
                </section>
            </article>

            

            
                <div id="disqus_thread"></div>
<script type="text/javascript">
    var disqus_shortname = 'nodejh'; 

     
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>

            

            
                <ul id="post-list" class="archive readmore">
    <h3>Read more</h3>
    
    
        
        <li>
            <a href="http://nodejh.com/post/how-to-vertically-middle-align-floated-elements-with-flexbox/">使用 Flexbox 使浮动元素垂直居中<aside class="dates">Jul 28</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/css-responsive-navigation-menu/">纯 CSS 实现响应式导航菜单<aside class="dates">Jul 28</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/vue2-tutorials-02-todolist/">实现一个TodoList - Vue2 Tutorials (二)<aside class="dates">Jul 17</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/electron-quick-start/">Electron 快速入门<aside class="dates">Jul 6</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/vue2-tutorials-01-quick-start/">快速入门 - Vue2 Tutorials (一)<aside class="dates">Jul 6</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/project-documentation-with-hexo-static-site-generator/">使用 Hexo 创建项目文档网站<aside class="dates">Jul 5</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/handy-mysql-commands/">常用 MySQL 命令<aside class="dates">Mar 30</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/understand-the-oracle-startup-process/">深入理解 Oracle 启动原理<aside class="dates">Mar 26</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/setting-environmental-variables-in-macos/">macOS/Linux 环境变量设置<aside class="dates">Mar 19</aside></a>
        </li>
        
   
    
        
        <li>
            <a href="http://nodejh.com/post/how-to-create-auto-increment-column-in-oracle/">在 Oracle 中设置自增列<aside class="dates">Feb 20</aside></a>
        </li>
        
   
</ul>
            

            <footer id="footer">
    
        <div id="social">

	
	
    <a class="symbol" href="https://www.facebook.com/nodejh">
        <i class="fa fa-facebook-square"></i>
    </a>
    
    <a class="symbol" href="https://www.github.com/nodejh">
        <i class="fa fa-github-square"></i>
    </a>
    
    <a class="symbol" href="https://www.twitter.com/nodejh">
        <i class="fa fa-twitter-square"></i>
    </a>
    


</div>

    
    <p class="small">
    
       © Copyright 2017 <i class="fa fa-heart" aria-hidden="true"></i> nodejh
    
    </p>
    <p class="small">
        Powered by <a href="http://www.gohugo.io/">Hugo</a> Theme By <a href="https://github.com/nodejh/hugo-theme-cactus-plus">nodejh</a>
    </p>
</footer>

        </section>

        <script src="http://nodejh.com/js/jquery-2.2.4.min.js"></script>
<script src="http://nodejh.com/js/main.js"></script>
<script src="http://nodejh.com/js/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>




  
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-84989670-1', 'auto');
ga('send', 'pageview');
</script>




<script>
var baiduAnalytics = '39843ea392201290bd6f76173d2e1633';
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?" + baiduAnalytics;
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();
</script>


    </body>
</html>
